/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package sorting_searching;

import DlinkedList.DNode;
import DlinkedList.MyDList;
import GoMail.Contacts;
import GoMail.Filter;
import folders2.UsersFile2;
import java.util.logging.Level;
import java.util.logging.Logger;
import stack.MyStack;
import stack.StackNode;
import java.io.*;
import java.util.*;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileSystemView;
import message.Message;
import message.MessageFolder;

/**
 *
 * @author Administrator
 */
public class SData implements SDataInterface
{
    private Object[] data;   //array which will be sorted and searched
    private Object element; // required element in data array
    private Object pivot;   //for sorting
    private int compareKey; //determine compare case
    private boolean sortedList;
    /**
     * This constructor is used to initialed new empty SData object
     */
    public SData()
    {
        data = null;
        element = null;
        pivot = null;
        compareKey = -1;    //case which not exsit
        sortedList = false;
    }
    /**
     * This constructor is used to create new SData object with
     * given array of data ,and given search elements
     * @param o new array of data which will be sorted and search in it
     * @param e searched element(element which i searched for it in data list)
     */
    public SData(Object[] o,Object e)
    {
        data = o;
        element = e;
        pivot = null;
    }
    /**
     * This method is used to get comparekey
     * @return comparekey
     */
    public int getCompareKey()
    {
        return compareKey;
    }
    /**
     * This method is used to set comparekey
     * @param compareKey new comparekey
     */
    public void setCompareKey(int compareKey)
    {
        this.compareKey = compareKey;
    }
    /**
     * This method is used to get data array
     * @return data array
     */
    public Object[] getData()
    {
        return data;
    }
    /**
     * This method is used to set data array
     * @param data  new data array
     */
    public void setData(Object[] data)
    {
        this.data = data;
    }
    /**
     * This method is used to get searched element
     * @return searched element
     */
    public Object getElement()
    {
        return element;
    }
    /**
     * This method is used to set searched element
     * @param element new searched element
     */
    public void setElement(Object element)
    {
        this.element = element;
    }
    /**
     * This method is used to data from stack to data array and ser search element
     * @param stack stack which contains data
     * @param o searched element
     */
    public void copyList(MyStack stack,Object o)
    {
        data = new Object[stack.size()];
        StackNode u = stack.getTop();
        int i = 0;
        while(u.getNext()!= null&& i < stack.size())
        {
            u = u.getNext();
            data[i] = u;//put stack elements in data array to search and sorting it
            i++;
        }
        element = o;
    }
    /**
     * This method is used to copy elements from doubly linked list to data list
     * and set element which we search for it
     * in this case data array will be of type array of DNode(doubly linked node)
     * @param list doubly linked list which contains data
     * @param o element which we search for it
     */
    public void copyList(MyDList list,Object o)
    {
        data = new Object[list.getSize()];
        DNode u = list.getHeader();
        int i = 0;
        while(u.getNext()!= list.getTrialer()&& i < list.getSize())
        {
            u = u.getNext();
            data[i] = u;    //put linked list elements in data array to search and sorting it
            i++;
        }
        element = o;
    }
    /**
     * This method is used to search array for this element
     * @return Object its type is same type of data array but in some case return index of element data array
     * if the element is found else return null
     */
    public Object binSearch()
    {
        SIndex u = new SIndex(0,data.length-1);  // object contains search indices
        boolean found = false;
        MyStack s =new MyStack();
        s.push(u);
        int mid = 0;
        while(!s.empty()&&!found)
        {
            u = (SIndex)s.pop();
            if(u.getStart() <= u.getEnd())
            {
                mid = (u.getEnd()+u.getStart())/2;
                int x = compare(mid,true,false);
                if(x == 0)
                {
                    if(compareKey == 1)
                    {
                        DNode v = (DNode)data[mid];
                        UsersFile2 q = (UsersFile2)v.getData();
                        UsersFile2 w = (UsersFile2)element;
                        if(q.getPassword().equalsIgnoreCase(w.getPassword()))
                            found = true;
                        else
                            return false;   ////////////////////////////////////
                    }
                    else if(compareKey == 11 || compareKey == 12 || compareKey == 13 ||compareKey == 14)
                        return mid;
                    else
                        found = true;       //if compare key not equal to 1 or 11
                }
                else if(x > 0)
                {
                    u.setValues(u.getStart(), mid-1);
                    s.push(u);
                }
                else
                {
                    u.setValues(mid+1, u.getEnd());
                    s.push(u);
                }
            }
            else
                found = false;
        }
        if(found == true)
            return data[mid]; //object is found & stack will be empty
        else
            return null;  //object not found
    }

    //under construction
    /**
     * This method is used to compare between elements
     * if this method is used by quickSort method then search field will be false
     * and compare is done between element from data array and pivot element
     * if this method is used by binary search method then sort field will be false
     * and compare is done between element from data array and the searched element
     * @param index index of element data array
     * @param search boolean variable is used to turn on searchCompare if it is true
     * @param sort boolean variable is used to turn on sortCompare if it is true
     * @return int result (0 , 1 , -1)
     */
    private int compare(int index , boolean search, boolean sort)
    {
        switch(compareKey)
        {
            case 0: //compare files names
            {
                if(search)
                {
                    File u = (File)data[index];
                    File v = (File)element;
                    return u.getName().compareToIgnoreCase(v.getName());
                    /* return negative value v after u lexicographicliy
                     * return positive value v before u lexicographicliy
                     * return zero v equla u lexicographicliy
                     * */
                }
                if(sort)
                {
                     File u = (File)pivot;
                     File v = (File) data[index];
                     return u.getName().compareToIgnoreCase(v.getName());
                }
                
            };break;
            case 1:         //identify user name  between Dnodes    work
            {
                if(search)
                {
                   DNode u = (DNode)data[index];
                   UsersFile2 v = (UsersFile2)u.getData();
                   UsersFile2 w = (UsersFile2)element;
                   return v.getUserName().compareToIgnoreCase(w.getUserName());
                }
                if(sort)
                {
                     DNode u = (DNode)data[index];
                     UsersFile2 v = (UsersFile2)u.getData();
                     UsersFile2 w = ((UsersFile2)((DNode)pivot).getData());
                     return(v.getUserName().compareToIgnoreCase(w.getUserName()));
                }
            };break;
            case 2:             //compare between node data && String
            {
                if(search)
                {
                    DNode u = (DNode)data[index];
                    DNode v = (DNode)element;       ////////////String?????????
                    return ((File)u.getData()).getName().compareToIgnoreCase(((File)v.getData()).getName());
                }
                if(sort)
                {
                     DNode u = (DNode)data[index];
                     DNode v = (DNode)pivot;      ////////String??????????????
                     return ((File)u.getData()).getName().compareToIgnoreCase(((File)v.getData()).getName());
                }
            };break;
            case 3:
            {
                if(search)
                {
                    File u = (File)data[index];
                    String v = (String)element;
                    return u.getName().compareToIgnoreCase(v);
                }
                if(sort)
                {
                    File u = (File)data[index];
                     String v = (String)pivot;
                        return u.getName().compareToIgnoreCase(v);
                }
            };break;
            case 4:
            {
                if(search)
                {
                    DNode u = (DNode)data[index];
                    Contacts v = (Contacts) u.getData();
                    return v.getName().compareToIgnoreCase((String)element);
                }
                if(sort)
                {
                    DNode u = (DNode)data[index];
                    Contacts v = (Contacts) u.getData();
                    DNode p = (DNode)pivot;
                    Contacts w = (Contacts)p.getData();
                    return v.getName().compareToIgnoreCase(w.getName());/////////////???????
                }
            };break;
            case 5:
            {
                /*if(search)
                {
                try
                {
                File u = (File) data[index];
                File v = (File) element;
                JFileChooser chooser = new JFileChooser();
                FileSystemView view = chooser.getFileSystemView();
                File info = view.getChild(u, "messInfo");
                Message uInfo = new Message();
                uInfo.readMessageInfo(info);
                File info2 = view.getChild(v, "messInfo");
                Message vInfo = new Message();
                vInfo.readMessageInfo(info2);
                return uInfo.getSendDate().compareTo(vInfo.getSendDate());
                } catch (IOException ex)
                {
                Logger.getLogger(SData.class.getName()).log(Level.SEVERE, null, ex);
                }
                }
                if(sort)
                {
                try
                {
                File u = (File) data[index];
                File v = (File) pivot;
                JFileChooser chooser = new JFileChooser();
                FileSystemView view = chooser.getFileSystemView();
                File info = view.getChild(u, "messInfo");
                Message uInfo = new Message();
                uInfo.readMessageInfo(info);
                File info2 = view.getChild(v, "messInfo");
                Message vInfo = new Message();
                vInfo.readMessageInfo(info2);
                return uInfo.getSendDate().compareTo(vInfo.getSendDate());
                } catch (IOException ex)
                {
                Logger.getLogger(SData.class.getName()).log(Level.SEVERE, null, ex);
                }
                }*/
                if(search)
                {
                     MessageFolder u = (MessageFolder) data[index];
                     MessageFolder v = (MessageFolder) element;
                     return u.getSms().getSendDate().compareTo(v.getSms().getSendDate());
                }
                if(sort)
                {
                     MessageFolder u = (MessageFolder) data[index];
                     MessageFolder v = (MessageFolder) pivot;
                     return v.getSms().getSendDate().compareTo(u.getSms().getSendDate());
                }
            };break;
            case 6:
            {
                if(search)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    String v = (String)element;
                    return u.getSms().getName().compareToIgnoreCase(v);
                }
                if(sort)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    MessageFolder v = (MessageFolder)pivot;
                    return u.getSms().getName().compareToIgnoreCase(v.getSms().getName());
                }
            };break;
            case 7:
            {
             if(search)
                {
                try
                {
                    File u = (File) data[index];
                    File v = (File) element;
                    JFileChooser chooser = new JFileChooser();
                    FileSystemView view = chooser.getFileSystemView();
                    File info = view.getChild(u, "messInfo");
                    Message uInfo = new Message();
                    uInfo.readMessageInfo(info);
                    File info2 = view.getChild(v, "messInfo");
                    Message vInfo = new Message();
                    vInfo.readMessageInfo(info2);
                    return uInfo.getReceiver().compareToIgnoreCase(vInfo.getReceiver());
                } catch (IOException ex)
                {
                    Logger.getLogger(SData.class.getName()).log(Level.SEVERE, null, ex);
                }
                }
                if(sort)
                {
                    try
                    {
                        File u = (File) data[index];
                        File v = (File) pivot;
                        JFileChooser chooser = new JFileChooser();
                        FileSystemView view = chooser.getFileSystemView();
                        File info = view.getChild(u, "messInfo");
                        Message uInfo = new Message();
                        uInfo.readMessageInfo(info);
                        File info2 = view.getChild(v, "messInfo");
                        Message vInfo = new Message();
                        vInfo.readMessageInfo(info2);
                        return uInfo.getReceiver().compareToIgnoreCase(vInfo.getReceiver());
                    } catch (IOException ex)
                    {
                        Logger.getLogger(SData.class.getName()).log(Level.SEVERE, null, ex);
                    }
                }
            };break;
            case 8:         //filter by subject
            {
                if(search)
                {
                    DNode w = (DNode)data[index];
                    Filter u = (Filter)w.getData();
                    String v = (String)element;
                    return u.getSubject().compareToIgnoreCase(v);
                }
                if(sort)
                {
                    DNode u = (DNode)data[index];
                    DNode v = (DNode)pivot;
                    Filter w = (Filter)u.getData();
                    Filter q = (Filter)v.getData();
                    return w.getSubject().compareToIgnoreCase(q.getSubject());
                }
            };break;
            case 9:             //filter by sender
            {
                if(search)
                {
                    DNode w = (DNode)data[index];
                    Filter u = (Filter)w.getData();
                    String v = (String)element;
                    return u.getSender().compareToIgnoreCase(v);
                }
                if(sort)
                {
                    DNode u = (DNode)data[index];
                    DNode v = (DNode)pivot;
                    Filter w = (Filter)u.getData();
                    Filter q = (Filter)v.getData();
                    return w.getSender().compareToIgnoreCase(q.getSender());
                }
            };break;
            case 10:
            {
                if(search)
                {
                    DNode w = (DNode)data[index];
                    MessageFolder u = (MessageFolder)w.getData();
                    String v = (String)element;
                    return u.getSms().getSubject().compareToIgnoreCase(v);
                }
                if(sort)
                {
                    DNode w = (DNode)data[index];
                    MessageFolder u = (MessageFolder)w.getData();
                    DNode q = (DNode)pivot;
                    MessageFolder v = (MessageFolder)q.getData();
                    return u.getSms().getSubject().compareToIgnoreCase(v.getSms().getSubject());
                }
            };break;
            case 11:
            {
                if(search)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    String v = (String)element;
                    String receiver = u.getSms().getReceiver().substring(0, u.getSms().getReceiver().indexOf("@"));
                    return receiver.compareToIgnoreCase(v);
                }
                if(sort)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    MessageFolder v = (MessageFolder)pivot;
                    String w = u.getSms().getReceiver().substring(0, u.getSms().getReceiver().indexOf("@"));
                    String q = v.getSms().getReceiver().substring(0, v.getSms().getReceiver().indexOf("@"));
                    return w.compareToIgnoreCase(q);
                }
            };break;
            case 12:
            {
                if(search)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    Date v = (Date)element;
                    return u.getSms().getSendDate().compareTo(v);
                }
                if(sort)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    MessageFolder v = (MessageFolder)pivot;
                    return u.getSms().getSendDate().compareTo(v.getSms().getSendDate());
                }
            };break;
            case 13:
            {
                if(search)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    String v = (String)element;
                    String sender = u.getSms().getSender();
                    return sender.compareToIgnoreCase(v);
                }
                if(sort)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    MessageFolder v = (MessageFolder)pivot;
                    String w = u.getSms().getSender();
                    String q = v.getSms().getSender();
                    return w.compareToIgnoreCase(q);
                }
            };break;
            case 14:
            {
                if(search)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    String v = (String)element;
                    String subject = u.getSms().getSubject();
                    return subject.compareToIgnoreCase(v);
                }
                if(sort)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    MessageFolder v = (MessageFolder)pivot;
                    String w = u.getSms().getSubject();
                    String q = v.getSms().getSubject();
                    return w.compareToIgnoreCase(q);
                }
            };break;
            case 15:
            {
                if(search)
                {

                }
                if(sort)
                {
                    MessageFolder u = (MessageFolder)data[index];
                    MessageFolder v = (MessageFolder)pivot;

                }
            };break;
        }
        return -500; //any number if all cases donnot realize
    }
    /**
     * This method is used to quick sort to data
     * @param from start index
     * @param to end index
     */
    private void quickSort(int from, int to)
    {
        SIndex u = new SIndex(from,to);
        MyStack stack = new MyStack();
        stack.push(u);
        while(!stack.empty())
        {
            u = (SIndex)stack.pop();
            if(u.getEnd()> u.getStart())
            {
                int p = partition(u.getStart(),u.getEnd());
               SIndex v = new SIndex(p+1, u.getEnd());
	                //u.setValues(p+1, u.getEnd());
	                stack.push(v);
	                SIndex w = new SIndex(u.getStart(), p);
	                //u.setValues(u.getStart(), p);
	                stack.push(w);
            }
        }
    }
    /**
     * This method is used to partitioned data to sort them
     * @param from start index
     * @param to end index
     * @return partitioned index
     */
    private int partition(int from, int to)
    {
        pivot = data[from];
        int i = from - 1;
        int j = to + 1;
        while(i < j)
        {
            i++;
            while(compare(i,false,true) < 0)
                i++;
            j--;
            while(compare(j,false,true) > 0)
                j--;
            if(i < j)
                swap(i,j);
        }
        return j;
    }
    /**
     * This method is used to swap two elements in data array
     * @param i first element
     * @param j second element
     */
    private void swap(int i, int j)
    {
        Object temp = data[i];
        data[i] = data[j];
        data[j] = temp;
    }
    //i made this method due to pivot
    //under construction
   /**
    * This method is used to to call quik sort method to sort data array
    */
    public void sortList()
    {
      this.quickSort(0, this.getData().length-1);
    }
}
